/*
 * Copyright (C) 2006-2007 Eskil Bylund
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;

using Gtk;
using Mono.Unix;

using DCSharp.Backend.Managers;
using DCSharp.Backend.Objects;
using DCSharp.Xml;

namespace DCSharp.Gui
{
	public class FileNodeView : ExtendedTreeView
	{
		private User user;
		private ActionGroup actionGroup;

		#region Constructors

		public FileNodeView(TreeModel model, User user) : base(model)
		{
			this.user = user;

			CanActivateMultipleRows = true;

			// User interface
			ActionEntry[] entries = new ActionEntry[] {
				new ActionEntry("Download", null, Catalog.GetString("_Download"), null,
					Catalog.GetString("Download the file or directory"),
					OnDownload),
				new ActionEntry("SaveTo", Stock.SaveAs, Catalog.GetString("_Save To..."), null,
					Catalog.GetString("Save file to a different directory"),
					OnSaveAs)
			};

			actionGroup = new ActionGroup("FileListingViewActions");
			actionGroup.Add(entries);

			// Columns
			TreeViewColumn column;
			CellRendererText textRenderer;
			CellRendererPixbuf pixbufRenderer;

			// Name
			column = new TreeViewColumn();
			column.Title = Catalog.GetString("Name");
			column.SortColumnId = (int)FileNodeStore.Column.Name;
			column.Resizable = true;
			column.Spacing = 3;
			AppendColumn(column);

			pixbufRenderer = new CellRendererPixbuf();
			column.PackStart(pixbufRenderer , false);
			column.SetCellDataFunc(pixbufRenderer, (Gtk.TreeCellDataFunc)SetPixbuf);

			textRenderer = new CellRendererText();
			column.PackStart(textRenderer , true);
			column.AddAttribute(textRenderer, "text", (int)FileNodeStore.Column.Name);

			// Size
			textRenderer = new CellRendererText();
			column = AppendColumn(Catalog.GetString("Size"), textRenderer,
				"text", (int)FileNodeStore.Column.Size);
			column.Resizable = true;
			column.SortColumnId = (int)FileNodeStore.Column.Bytes;

			// TTH
			textRenderer = new CellRendererText();
			textRenderer.Ellipsize = Pango.EllipsizeMode.Middle;
			column = AppendColumn(Catalog.GetString("TTH"), textRenderer,
				"text", (int)FileNodeStore.Column.TTH);
			column.Expand = true;
			column.Resizable = true;
			column.SortColumnId = (int)FileNodeStore.Column.TTH;
		}

		#endregion

		#region Properties

		public User User
		{
			get { return user; }
		}

		#endregion

		#region Methods

		public TreePath ExpandToPathString(string path)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			if (path.StartsWith(new string(System.IO.Path.DirectorySeparatorChar, 1)))
			{
				path = path.Substring(1);
			}

			TreeIter iter;
			TreePath treePath = null;
			if (!Model.GetIterFirst(out iter))
			{
				return null;
			}

			int i = 0;
			string[] dirs = path.Split(System.IO.Path.DirectorySeparatorChar);

			bool hasIter = false;
			do
			{
				string name = Model.GetValue(iter,
					(int)FileNodeStore.Column.Name) as string;
				if (name == dirs[i])
				{
					treePath = Model.GetPath(iter);

					// Load any child iters
					ExpandToPath(treePath);

					hasIter = Model.IterChildren(out iter, iter);
					if (hasIter)
					{
						i++;
						continue;
					}
					break;
				}
				hasIter = Model.IterNext(ref iter);
			}
			while (hasIter && i < dirs.Length);

			return treePath;
		}

		protected override void OnPopulatePopup(Menu menu)
		{
			menu.Add(actionGroup["Download"].CreateMenuItem());
			menu.Add(actionGroup["SaveTo"].CreateMenuItem());

			base.OnPopulatePopup(menu);
		}

		protected override void OnRowActivated(TreePath path,
			TreeViewColumn column)
		{
			TreeIter iter;
			if (!Model.GetIter(out iter, path))
			{
				return;
			}

			FileNode file = Model.GetValue(iter,
				(int)FileNodeStore.Column.Object) as FileNode;
			if (file != null && file.TTH != null)
			{
				//string filePath = System.IO.Path.Combine(BuildPath(Model, iter),
				//	file.Name);

				RemoteFileInfo remoteFile = new RemoteFileInfo(file.Name,
					file.Size, file.TTH);

				Globals.Runtime.DownloadManager.Download(remoteFile, user);
				return;
			}
			base.OnRowActivated(path, column);
		}

		#region Downloading

		private void Download(DirectoryNode directory, string path,
			string target)
		{
			Download(directory, path, target, directory.Name);
		}

		private void Download(DirectoryNode directory, string path, string target,
			string name)
		{
			target = System.IO.Path.Combine(target, name);

			foreach (DirectoryNode childDir in directory.Directories)
			{
				Download(childDir, System.IO.Path.Combine(path, childDir.Name),
					target);
			}
			foreach (FileNode file in directory.Files)
			{
				if (file.TTH != null)
				{
					RemoteFileInfo remoteFile = new RemoteFileInfo(file.Name,
						file.Size, file.TTH);

					Globals.Runtime.DownloadManager.Download(remoteFile, user,
						target);
				}
			}
		}

		private string BuildPath(TreeModel model, TreeIter iter)
		{
			TreeIter parent;
			if (model.IterParent(out parent, iter))
			{
				DirectoryNode directory = model.GetValue(parent,
					(int)FileNodeStore.Column.Object) as DirectoryNode;
				if (directory != null)
				{
					return System.IO.Path.Combine(BuildPath(model, parent),
						directory.Name);
				}
			}
			return String.Empty;
		}

		#endregion

		private void SetPixbuf(TreeViewColumn column, CellRenderer renderer,
			TreeModel model, TreeIter iter)
		{
			CellRendererPixbuf pixbufRenderer = renderer as CellRendererPixbuf;
			if (pixbufRenderer != null)
			{
				object obj = model.GetValue(iter, (int)FileNodeStore.Column.Object);

				FileNode file = obj as FileNode;
				if (file != null)
				{
					pixbufRenderer.Pixbuf = Util.GetIconFromPath(file.Name);
				}
				else if (obj is DirectoryNode)
				{
					pixbufRenderer.Pixbuf = RenderIcon(Stock.Directory,
						IconSize.Menu, String.Empty);
				}
			}
		}

		private void OnDownload(object obj, EventArgs args)
		{
			TreeIter[] iters = GetSelectedIters();
			foreach (TreeIter iter in iters)
			{
				Download(iter, Globals.Runtime.Settings.DownloadDirectory);
			}
		}

		private void OnSaveAs(object obj, EventArgs args)
		{
			TreeIter[] iters = GetSelectedIters();
			if (iters.Length == 1)
			{
				string name = Model.GetValue(iters[0],
					(int)FileNodeStore.Column.Name) as string;

				string filename = SaveToDialog.GetFilename(name, Toplevel as Window);
				if (filename != null)
				{
					Download(iters[0], System.IO.Path.GetDirectoryName(filename),
						System.IO.Path.GetFileName(filename));
				}
			}
			else
			{
				string folder = SaveToDialog.GetFolder(Toplevel as Window);
				if (folder != null)
				{
					foreach (TreeIter iter in iters)
					{
						Download(iter, folder);
					}
				}
			}
		}

		private void Download(TreeIter iter, string target)
		{
			Download(iter, target, null);
		}

		private void Download(TreeIter iter, string target, string name)
		{
			DirectoryNode directory = Model.GetValue(iter,
				(int)FileNodeStore.Column.Object) as DirectoryNode;
			if (directory != null)
			{
				string path = System.IO.Path.Combine(BuildPath(Model, iter),
					directory.Name);

				if (name != null)
				{
					Download(directory, path, target, name);
				}
				else
				{
					Download(directory, path, target);
				}
			}

			FileNode file = Model.GetValue(iter,
				(int)FileNodeStore.Column.Object) as FileNode;
			if (file != null)
			{
				RemoteFileInfo remoteFile = new RemoteFileInfo(name ?? file.Name,
					file.Size, file.TTH);

				Globals.Runtime.DownloadManager.Download(remoteFile, user, target);
			}
		}

		#endregion
	}
}
